package com.ikingtech.framework.sdk.oss.embedded.core.minio;

import com.ikingtech.framework.sdk.oss.embedded.core.AbstractFileTemplate;
import com.ikingtech.framework.sdk.oss.embedded.core.OssInitMultiUploadResponse;
import com.ikingtech.framework.sdk.oss.embedded.core.OssResponse;
import com.ikingtech.framework.sdk.oss.embedded.exception.OssEmbeddedException;
import com.ikingtech.framework.sdk.utils.Tools;
import io.minio.*;
import io.minio.errors.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
public class MinioFileTemplate extends AbstractFileTemplate {

    private final MinioClient client;

    /**
     * 创建桶
     *
     * @param bucketName 桶名称
     */
    @Override
    public void createBucket(String bucketName) {
        try {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (ServerException |
                 InsufficientDataException |
                 ErrorResponseException |
                 NoSuchAlgorithmException |
                 InvalidKeyException |
                 InvalidResponseException |
                 XmlParserException |
                 InternalException |
                 IOException e) {
            throw new OssEmbeddedException("[N/A]create bucket error." + e.getMessage());
        }
    }

    @Override
    public void removeBucket(String bucketName) {
        throw new OssEmbeddedException("[N/A]unsupported operation[removeBucket]");
    }

    /**
     * 上传文件
     *
     * @param path 对象路径
     * @param objectName 对象名称
     * @param stream 文件流
     * @param contentType 媒体类型
     * @return 执行结果
     */
    @Override
    public String putObject(String path, String objectName, InputStream stream, String contentType) {
        try {
            String formattedObjectName = this.objectNameFormat(objectName);
            PutObjectArgs args = PutObjectArgs.builder()
                    .object(formattedObjectName)
                    .bucket(path)
                    .stream(stream, stream.available(), -1)
                    .contentType(Tools.Str.isBlank(contentType) ? MediaType.APPLICATION_OCTET_STREAM_VALUE : contentType)
                    .build();
            client.putObject(args);
            return formattedObjectName;
        } catch (ServerException |
                 InsufficientDataException |
                 ErrorResponseException |
                 NoSuchAlgorithmException |
                 InvalidKeyException |
                 InvalidResponseException |
                 XmlParserException |
                 InternalException |
                 IOException e) {
            throw new OssEmbeddedException("[N/A]put object error." + e.getMessage());
        }
    }

    /**
     * 分片上传文件
     *
     * @param path        对象路径
     * @param objectName  对象名称
     * @param contentType 文件传输类型
     * @return 执行结果
     */
    @Override
    public OssInitMultiUploadResponse initMultiUpload(String path, String objectName, String contentType) {
        throw new OssEmbeddedException("[N/A]unsupported operation[initMultiUpload]");
    }

    /**
     * 分片上传文件
     *
     * @param path           对象路径
     * @param partObjectName 分片文件名
     * @param uploadId       分片上传编号
     * @param partNo         分片序号
     * @param stream         文件流
     * @return 分片ETag
     */
    @Override
    public String putObjectSlice(String path, String partObjectName, String uploadId, Integer partNo, InputStream stream) {
        throw new OssEmbeddedException("[N/A]unsupported operation[putObjectSlice]");
    }

    /**
     * 完成分片上传文件
     *
     * @param path       对象路径
     * @param initResponse 分片上传任务创建结果
     * @param parts      分片信息，key为分片序号，value为分片上传返回的ETag
     * @return 执行结果
     */
    @Override
    public String completeMultiUpload(String path, OssInitMultiUploadResponse initResponse, Map<Integer, String> parts) {
        throw new OssEmbeddedException("[N/A]unsupported operation[completeMultiUpload]");
    }

    /**
     * 下载文件
     *
     * @param bucketName 桶名称
     * @param objectName 对象名称
     * @return 文件流
     */
    @Override
    public OssResponse getObject(String bucketName, String objectName) {
        try {
            GetObjectResponse minioResult = client.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
            return new OssResponse(minioResult.headers().get("Content-Type"), minioResult);
        }  catch (ServerException |
                  InsufficientDataException |
                  ErrorResponseException |
                  NoSuchAlgorithmException |
                  InvalidKeyException |
                  InvalidResponseException |
                  XmlParserException |
                  InternalException |
                  IOException e) {
            throw new OssEmbeddedException("[N/A]get object error." + e.getMessage());
        }
    }

    /**
     * 删除桶
     *
     * @param bucketName 桶名称
     * @param objectName 对象名称
     */
    @Override
    public void removeObject(String bucketName, String objectName) {
        try {
            this.client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (ServerException |
                 InsufficientDataException |
                 ErrorResponseException |
                 NoSuchAlgorithmException |
                 InvalidKeyException |
                 InvalidResponseException |
                 XmlParserException |
                 InternalException |
                 IOException e) {
            throw new OssEmbeddedException("[N/A]remove object error." + e.getMessage());
        }
    }
}
